#include "Camera.h"

#include <Windows.h>
#include <gl\GLU.h>

const float_t STEP_SIZE = 10.0f;

Camera::Camera()
	:
m_fForwardStep(STEP_SIZE),
m_fBackwardStep(STEP_SIZE),
m_fRightStep(STEP_SIZE),
m_fLeftStep(STEP_SIZE),
m_fCurrentPitch(0),
MAX_PITCH(300), // Half the screen height
CAMERA_BUFFER(0.1f)
{
	// Init vectors
	memset(m_vForward, 0, sizeof(M3DVector3f));
	memset(m_vUp, 0, sizeof(M3DVector3f));
	memset(m_vSide, 0, sizeof(M3DVector3f));
	memset(m_vPosition, 0, sizeof(M3DVector3f));

	m_vForward[2] = -1.0f;
	m_vUp[1]      =  1.0f;
	m_vSide[0]    =  1.0f;

	// Back camera up a bit
	m_vPosition[2] = 10.0f;
}


Camera::~Camera()
{

}

void Camera::SetLookAt() const
{
	// Reset model-view matrix
	glLoadIdentity();
	// Set camera target
	M3DVector3f _target;
	m3dAddVectors3(_target, m_vPosition, m_vForward);
	// Calculate view matrix
	gluLookAt(m_vPosition[0], m_vPosition[1], m_vPosition[2], _target[0], _target[1], _target[2], m_vUp[0], m_vUp[1], m_vUp[2]);
}

const M3DVector3f* const Camera::GetTransform() const
{
	return (M3DVector3f*)m_vPosition;
}

void Camera::MoveForward(float_t argDeltaTime)
{
	// Move camera forward
	M3DVector3f _translation;
	memcpy(_translation, m_vForward, sizeof(m_vForward));
	m3dScaleVector3(_translation, CAMERA_BUFFER);

	m3dAddVectors3(m_vPosition, m_vPosition, _translation);
}

void Camera::MoveBackward(float_t argDeltaTime)
{
	// Move camera back
	M3DVector3f _translation;
	memcpy(_translation, m_vForward, sizeof(m_vForward));
	m3dScaleVector3(_translation, CAMERA_BUFFER);

	m3dSubtractVectors3(m_vPosition, m_vPosition, _translation);
}

void Camera::MoveRight(float_t argDeltaTime)
{
	M3DVector3f _translation;
	memcpy(_translation, m_vSide, sizeof(m_vSide));
	m3dScaleVector3(_translation, CAMERA_BUFFER); // Time based increments are lagging camera movement

	// Update the position and the forward vector
	m3dAddVectors3(m_vPosition, m_vPosition, _translation);
}

void Camera::MoveLeft(float_t argDeltaTime)
{
	M3DVector3f _translation;
	memcpy(_translation, m_vSide, sizeof(m_vSide));
	m3dScaleVector3(_translation, CAMERA_BUFFER);

	// Update the position and the forward vector
	m3dSubtractVectors3(m_vPosition, m_vPosition, _translation);
}

void Camera::MoveUp(float_t argDeltaTime)
{
	M3DVector3f _translation;
	memcpy(_translation, m_vUp, sizeof(m_vUp));
	m3dScaleVector3(_translation, CAMERA_BUFFER);

	m3dAddVectors3(m_vPosition, m_vPosition, _translation);
}

void Camera::MoveDown(float_t argDeltaTime)
{
	M3DVector3f _translation;
	memcpy(_translation, m_vUp, sizeof(m_vUp));
	m3dScaleVector3(_translation, CAMERA_BUFFER);

	m3dSubtractVectors3(m_vPosition, m_vPosition, _translation);
}

void Camera::RotateCameraYawCC(float_t argDeltaX)
{
	M3DMatrix33f _matRotation;
	// Create a rotation around the world up vector
	m3dRotationMatrix33(_matRotation, CAMERA_BUFFER / 10, 0.0f, 1.0f, 0.0f);

	// Update the camera's forward vector 
	m3dRotateVector(m_vForward, m_vForward, _matRotation);
	// Update the camera's side vector
	m3dRotateVector(m_vSide, m_vSide, _matRotation);
}

void Camera::RotateCameraYawCW(float_t argDeltaX)
{
	M3DMatrix33f _matRotation;
	// Create a rotation around the world up vector
	m3dRotationMatrix33(_matRotation, CAMERA_BUFFER / 10, 0.0f, -1.0f, 0.0f);

	// Update the camera's forward vector 
	m3dRotateVector(m_vForward, m_vForward, _matRotation);
	// Update the camera's side vector
	m3dRotateVector(m_vSide, m_vSide, _matRotation);
}